﻿using System;
using System.Collections.Generic;
using System.Text;

namespace InfoJetSoft.Service.XPath.Exprs
{
    class NumberFunctions
    {
        //CID 0795 //2011.02.17 //Begin
        public static double number(ExprContext context, object value)
        {
            if (value is double)
            {
                return (double)value;
            }
            else if (value is bool)
            {
                if ((bool)value)
                {
                    return 1.0;
                }
                else
                {
                    return 0.0;
                }
            }
            else if (value is string)
            {
                try
                {
                    double doubleValue = double.Parse((string)value);
                    return doubleValue;
                }
                catch (Exception e)
                {
                    return double.NaN;
                }
            }
            else if (value is INodeList)
            {
                INodeList nodeList = (INodeList)value;
                if (nodeList.Count > 0)
                {
                    object node = nodeList.Get(0);
                    string nodeValue = context.Calculator.GetNodeValue(node);
                    try
                    {
                        double doubleValue = double.Parse(nodeValue);
                        return doubleValue;
                    }
                    catch (Exception e)
                    {
                        return double.NaN;
                    }
                }
                else
                {
                    return double.NaN;
                }
            }
            else
            {
                throw new ExprException("Unsupported data type.");
            }
        }
        //CID 0795 //2011.02.17 //End

        //CID 0796 //2011.02.26 //Begin
        public static double floor(ExprContext context, object value)
        {
            double doubleValue = number(context, value);
            return Math.Floor(doubleValue);
        }
        //CID 0796 //2011.02.26 //end

        //CID 0796 //2011.02.26 //Begin
        public static double ceiling(ExprContext context, object value)
        {
            double doubleValue = number(context, value);
            return Math.Ceiling(doubleValue);
        }
        //CID 0796 //2011.02.26 //end

        //CID 0796 //2011.02.26 //Begin
        public static double round(ExprContext context, object value)
        {
            double doubleValue = number(context, value);
            return Math.Round(doubleValue);
        }
        //CID 0796 //2011.02.26 //end

        //CID 0796 //2011.02.27 //Begin
        public static double sum(ExprContext context, object nodes)
        {
            if (nodes is INodeList)
            {
                INodeList nodeList = (INodeList)nodes;
                double sumValue = 0.0;
                foreach (object node in nodeList)
                {
                    string nodeValue = context.Calculator.GetNodeValue(node);
                    double doubleValue = NumberFunctions.number(context, nodeValue);
                    sumValue = sumValue + doubleValue;
                }
                return sumValue;
            }
            else
            {
                throw new Exception("sum() needs node list.");
            }
        }
        //CID 0796 //2011.02.27 //end

        //CID 0796 //2011.02.26 //Begin
        public static object CallFunction(ExprContext context, string funcName, List<object> args)
        {
            if (funcName.Equals("number"))
            {
                if (args.Count == 0)
                {
                    object contextNodes = context.Calculator.GetContextNodes(false);
                    return NumberFunctions.number(context, contextNodes);
                }
                else if (args.Count == 1)
                {
                    return NumberFunctions.number(context, args[0]);
                }
                else
                {
                    throw new ExprException("Wrong parameters in number().");
                }
            }
            else if (funcName.Equals("floor"))
            {
                if (args.Count == 1)
                {
                    return NumberFunctions.floor(context, args[0]);
                }
                else
                {
                    throw new ExprException("Wrong parameters in number().");
                }
            }
            else if (funcName.Equals("ceiling"))
            {
                if (args.Count == 1)
                {
                    return NumberFunctions.ceiling(context, args[0]);
                }
                else
                {
                    throw new ExprException("Wrong parameters in number().");
                }
            }
            else if (funcName.Equals("round"))
            {
                if (args.Count == 1)
                {
                    return NumberFunctions.round(context, args[0]);
                }
                else
                {
                    throw new ExprException("Wrong parameters in number().");
                }
            }
            else if (funcName.Equals("sum"))
            {
                if (args.Count == 1)
                {
                    return NumberFunctions.sum(context, args[0]);
                }
                else
                {
                    throw new ExprException("Wrong parameters in number().");
                }
            }
            else
            {
                return null;
            }
        }
        //CID 0796 //2011.02.27 //End

        //CID 0811 //2011.03.01 //Begin
        public static double Min(ExprContext context, INodeList nodeList)
        {
            bool inited = false;
            double min = double.NaN;
            foreach (object node in nodeList)
            {
                string nodeValue = context.Calculator.GetNodeValue(node);
                double nodeDoubleValue = NumberFunctions.number(context, nodeValue);
                if (!double.IsNaN(nodeDoubleValue))
                {
                    if (!inited)
                    {
                        min = nodeDoubleValue;
                        inited = true;
                    }
                    else
                    {
                        if (nodeDoubleValue < min)
                        {
                            min = nodeDoubleValue;
                        }
                    }
                }
            }
            return min;
        }
        //CID 0811 //2011.03.01 //End

        //CID 0811 //2011.03.01 //Begin
        public static double Max(ExprContext context, INodeList nodeList)
        {
            bool inited = false;
            double max = double.NaN;
            foreach (object node in nodeList)
            {
                string nodeValue = context.Calculator.GetNodeValue(node);
                double nodeDoubleValue = NumberFunctions.number(context, nodeValue);
                if (!double.IsNaN(nodeDoubleValue))
                {
                    if (!inited)
                    {
                        max = nodeDoubleValue;
                        inited = true;
                    }
                    else
                    {
                        if (nodeDoubleValue > max)
                        {
                            max = nodeDoubleValue;
                        }
                    }
                }
            }
            return max;
        }
        //CID 0811 //2011.03.01 //End
    }
}
